from pyx_package.script import BaseBehavior
from pyx_package.ps_paramete import PsParameter

import os
import json
import threading

from urllib.request import urlopen
from urllib.request import Request
from urllib.error import URLError
from urllib.parse import urlencode
from urllib.parse import quote_plus
from playsound import playsound
 
PYX_MODULE_NAME = "text-to-speech-baidu"

class ScriptBehavior(BaseBehavior):

    def __init__(self) -> None:
        super().__init__()
        
        self.SetExeMode("function")

        self.InitVars()

        self.InitParams()

    def InitVars(self):

        self.TTS_URL = 'http://tsn.baidu.com/text2audio'
        self.TOKEN_URL = 'http://openapi.baidu.com/oauth/2.0/token'


    def InitParams(self):

        #文本内容
        self.p_content = self.CreateParam("content", "文本内容", PsParameter.Input, str, "")

        #请求配置
        self.p_app_config = self.CreateParam("API app config", "API应用配置", PsParameter.Input, None)

        #API_KEY
        self.p_api_key = self.CreateParam("api key", "BaiDu API KEY", PsParameter.Input, str, "")
        self.p_app_config.AddChild(self.p_api_key)

        #SECRET_KEY
        self.p_secret_key = self.CreateParam("secret key", "BaiDu SECRET KEY", PsParameter.Input, str, "")
        self.p_app_config.AddChild(self.p_secret_key)

        #token
        self.p_token = self.CreateParam("token", "Token", PsParameter.Input, str, "")
        self.p_app_config.AddChild(self.p_token)

        #声音选择
        self.p_sound_per = self.CreateParam("sound per", "声优", PsParameter.Input, str, "")
        self.p_sound_per.value_input_mode = PsParameter.ComboBoxMode
        self.p_sound_per.SetOptionitems(['度小美', '度小宇', '度逍遥', '度丫丫', '度逍遥（精品）', '度小鹿', '度博文', '度小童', '度小萌', '度米朵', '度小娇'])
        self.p_app_config.AddChild(self.p_sound_per)

        #中间文件路径
        self.p_save_path = self.CreateParam("save path", "音频中间文件路径", PsParameter.Input, str, "")
        temp_file = os.getenv("TMP")
        temp_file = temp_file.replace("\\", "/")
        temp_file = temp_file.strip("/")

        self.p_save_path.value = temp_file + "/pythonx_baidu_sound.mp3"

        self.p_app_config.AddChild(self.p_save_path)

    def GetPer(self):
        '''
            获取指定声优的id
        '''

        per_str = self.p_sound_per.value

        if per_str == "度小美":
            return "0"
        if per_str == "度小宇":
            return "1"
        if per_str == "度逍遥":
            return "3"
        if per_str == "度丫丫":
            return "4"
        if per_str == "度逍遥（精品）":
            return "5003"
        if per_str == "度小鹿":
            return "5118"
        if per_str == "度博文":
            return "106"
        if per_str == "度小童":
            return "110"
        if per_str == "度小萌":
            return "111"
        if per_str == "度米朵":
            return "103"
        if per_str == "度小娇":
            return "5"

    def DoStep(self):

        content = self.p_content.value
        if content == None or content == "None" or len(content) < 3: return 
        
        if len(self.p_token.value) < 10:
            token = self.fetch_token()
        else:
            token = self.p_token.value

        tex = quote_plus(self.p_content.value)  # 此处TEXT需要两次urlencode

        params = {'tok':token , 'tex': tex, 'cuid': "quickstart",
                'lan': 'zh', 'ctp': 1, 'per':self.GetPer()}  # lan ctp 固定参数

        data = urlencode(params)
        #请求
        req = Request(self.TTS_URL, data.encode('utf-8'))
        #是否有错误
        has_error = False
        try:
            f = urlopen(req)
            result_str = f.read()

            headers = dict((name.lower(), value) for name, value in f.headers.items())

            has_error = ('content-type' not in headers.keys() or headers['content-type'].find('audio/') < 0)
        except  URLError as err:
            self.Debug('接口调用失败，错误代码 : ' + str(err.code), "error")
            result_str = err.read()
            has_error = True

        with open(self.p_save_path.value, 'wb') as of:
            of.write(result_str)

        if has_error:
            result_str = str(result_str, 'utf-8')
            self.Debug("TTs 错误:" + result_str, "error")

        else:
            t = threading.Thread(target = self.Speek)
            t.start()
            
    def Speek(self):
        if os.path.exists(self.p_save_path.value):
            playsound(self.p_save_path.value)

    def fetch_token(self):
        params = {'grant_type': 'client_credentials',
                'client_id': self.p_api_key.value,
                'client_secret': self.p_secret_key.value}
        post_data = urlencode(params)
        post_data = post_data.encode('utf-8')
        req = Request(self.TOKEN_URL, post_data)

        try:
            f = urlopen(req, timeout=5)
            result_str = f.read()
        except URLError as err:
            self.Debug('token 获取错误，错误码 : ' + str(err.code), "warning")
            result_str = err.read()

        result_str = result_str.decode()
        result = json.loads(result_str)

        if ('access_token' in result.keys() and 'scope' in result.keys()):
            if not 'audio_tts_post' in result['scope'].split(' '):
                self.Debug('请检查TTS', "warning")
                return None
            print(result['access_token'])
            return result['access_token']
        else:
            print ('API_KEY 或者 SECRET_KEY 不正确，token获取失败', "warning")
            return None